#include "Configuration.h"
#include "Log.h"
#include "ThreadPool.h"
#include "Request.h"
#include "Task.h"
#include "Network.h"
#include <mysql/mysql.h>

#define BACKLOG 10
#define MAXEVENTS 1024  // 可根据实际调整 

int fields[2];
Configuration conf;
ThreadPool tpool;

void sighandler(int signum){
    write(fields[1], "exit", 5);
}

void enable_logging(const char* logfile, const char* loglevel)
{
    if (logfile) {
        log_set_output(logfile);
    } else {
        log_set_output("CloudDisk.log");
    }
    if (loglevel) {
        LogLevel level = LOG_WARN;
        if (strcmp(loglevel, "TRACE") == 0) {
            level = LOG_TRACE;
        } else if (strcmp(loglevel, "DEBUG") == 0) {
            level = LOG_DEBUG;
        } else if (strcmp(loglevel, "INFO") == 0) {
            level = LOG_INFO;
        } else if (strcmp(loglevel, "WARN") == 0) {
            level = LOG_WARN;
        } else if (strcmp(loglevel, "ERROR") == 0) {
            level = LOG_ERROR;
        } else if (strcmp(loglevel, "FATAL") == 0) {
            level = LOG_FATAL;
        }
        log_set_level(level);
    } else {
        log_set_level(LOG_WARN);    // 默认日志级别
    }
}

int main(int argc,char* argv[])
{
    pipe(fields);

    pid_t pid = fork();
    switch (pid) {
    case -1:
        error(1, errno, "fork()");
    case 0:     
        break;
    default:    
        // 父进程关闭读端
        close(fields[0]);
        // 注册信号处理函数
        signal(SIGINT, sighandler);
        // 等待子进程退出
        waitpid(pid, NULL, 0);
        exit(0);
    }

    // 子进程关闭写端
    close(fields[1]);

    setpgid(0, 0);  // 将子进程和终端断开，这样终端的控制字符如 [Ctrl+C] 对子进程不起作用

    // 读取配置文件
    configuration_init(&conf);
    configuration_load(&conf, "CloudDisk.ini");
    // configuration_display(&conf);

    // 开启日志
    const char* logfile = configuration_get(&conf, "LOG_FILE");
    const char* loglevel = configuration_get(&conf, "LOG_LEVEL");
    enable_logging(logfile, loglevel);

    // 初始化 mysql 库
    if (mysql_library_init(0, NULL, NULL)) {
        log_fatal("mysql_library_init() failed");
        exit(1);
    }
    
    // 设置随机种子
    srand(time(NULL));

    // 启动线程池
    int cores = get_nprocs_conf();
    threadpool_init(&tpool, cores * 2);
    log_info("threadpool_init() success!");

    // 监听端口
    char* port = configuration_get(&conf, "PORT");
    if (!port) {
        log_fatal("PORT has not configurated!");
        exit(1);
    }
    int listenfd = tcp_listen(port);
    if (listenfd == -1) {
        log_fatal("tcp_listen() failed\n");
    }
    log_info("tcp_listen() success!");

    int epfd = epoll_create(1);
    epoll_add(epfd, fields[0]);
    epoll_add(epfd, listenfd);

    // 事件循环
    struct epoll_event revents[MAXEVENTS];
    for(;;) {
        int nready = epoll_wait(epfd, revents, MAXEVENTS, -1); // 无限期阻塞
                                                                     
        for (int i = 0; i < nready; i++) {
            int fd = revents[i].data.fd;

            if (fd == fields[0]) {
                // 管道有数据：线程池有序退出
                threadpool_wait(&tpool);
                threadpool_destroy(&tpool);
                goto end;
            } else if (fd == listenfd) {
                // 有新的连接到来
                struct sockaddr_storage ss;
                socklen_t addrlen = sizeof(ss);
                int connfd = accept(listenfd, (struct sockaddr*)&ss, &addrlen);
                
                char ipstr[50];
                inet_ntop(ss.ss_family, (struct sockaddr*)getipaddr((struct sockaddr*)&ss), ipstr, 50);
                char message[80];
                sprintf(message, "new connection from %s", ipstr);
                log_info(message);
                epoll_add(epfd, connfd);
            } else {
                // 客户端有数据：处理请求
                int length;
                recv(fd, &length, sizeof(int), MSG_WAITALL);

                Param* param = (Param*) calloc(1, sizeof(Param));
                param->epfd = epfd;
                param->connfd = fd;
                recv(fd, &param->req, length, MSG_WAITALL);
                
                epoll_del(epfd, fd);    // epoll实例不再监听fd

                switch (param->req.type) {
                case REQ_UPLOAD_FILE:
                    threadpool_add_task(&tpool, upload_file, param);
                    break;
                case REQ_REGISTER:
                    threadpool_add_task(&tpool, do_register, param);
                    break;
                /* other cases */
                }
            } 
        }
    }

end:
    mysql_library_end();
    return 0;
}
